#pragma once
#include "Vector3d.h"

#include "Point3d.h"

#include <exception>
#include <math.h>

namespace Geometry
  {
  Vector3d::Vector3d()
    : m_x(0.0), m_y(0.0), m_z(0.0)
    {

    }

  Vector3d::Vector3d(double i_x, double i_y, double i_z)
    : m_x(i_x), m_y(i_y), m_z(i_z)
    {

    }


  double Vector3d::operator[](size_t i_index) const
    {
    if (i_index > 2)
      {
      throw std::exception("Vector3d operator[]: argument out of range");
      }
    switch (i_index)
      {
      case 0:
        return m_x;
      case 1:
        return m_y;
      case 2:
        return m_z;
      default:
        throw std::exception("Vector3d operator[]: unsupported case");
      }
    }

  double Vector3d::GetLength() const
    {
    double res = 0.0;
    res += m_x*m_x;
    res += m_y*m_y;
    res += m_z*m_z;
    return sqrt(res);
    }

  Vector3d& Vector3d::operator += (const Vector3d& i_other)
    {
    m_x += i_other.m_x;
    m_y += i_other.m_y;
    m_z += i_other.m_z;
    return *this;
    }

  Vector3d& Vector3d::operator -= (const Vector3d& i_other)
    {
    m_x -= i_other.m_x;
    m_y -= i_other.m_y;
    m_z -= i_other.m_z;
    return *this;
    }

  Vector3d& Vector3d::operator *= (double i_scalar)
    {
    m_x *= i_scalar;
    m_y *= i_scalar;
    m_z *= i_scalar;
    return *this;
    }

  Vector3d operator+(Vector3d i_left, const Vector3d& i_right)
    {
    return i_left += i_right;
    }

  Vector3d operator-(Vector3d i_left, const Vector3d& i_right)
    {
    return i_left -= i_right;
    }

  Vector3d operator*(Vector3d i_vector, double i_scalar)
    {
    return i_vector *= i_scalar;
    }

  double operator*(const Vector3d& i_left, const Vector3d& i_right)
    {
    double res = 0.0;
    res += i_left[0] * i_right[0];
    res += i_left[1] * i_right[1];
    res += i_left[2] * i_right[2];
    return res;
    }

  Vector3d operator^(const Vector3d& i_left, const Vector3d& i_right)
    {
    double res_x = i_left[1] * i_right[2] - i_left[2] * i_right[1];
    double res_y = -(i_left[0]*i_right[2] - i_left[2] * i_right[0]);
    double res_z = i_left[0] * i_right[1] - i_left[1] * i_right[0];
    return Vector3d(res_x, res_y, res_z);
    }

  bool operator == (const Vector3d& i_left, const Vector3d& i_right)
    {
    return i_left[0] == i_right[0] && i_left[1] == i_right[1] && i_left[2] == i_right[2];
    }

  double MixedProduct(const Vector3d& i_vec_1, const Vector3d& i_vec_2, const Vector3d& i_vec_3)
    {
    return (i_vec_1 ^ i_vec_2) * i_vec_3;
    }
   
  }

